//
// Created by wlk12 on 2024/2/29.
//
#include <iostream>
#include <mutex>
#include <atomic>

class Singleton
{
public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    static Singleton* get()
    {
        static Singleton singleton;
        return &singleton;
    }

    [[nodiscard]] int getData() const
    {
        return this->data;
    }

    void setData(int value)
    {
        this->data = value;
    }

private:
    Singleton() = default;
    ~Singleton()
    {
        std::cout << "Singleton1 Destruct." << std::endl;
    }

    int data{};
};

class Singleton2
{
public:
    Singleton2(const Singleton2&) = delete;
    Singleton2& operator=(const Singleton2&) = delete;

    static Singleton2* get()
    {
        if (instance == nullptr)
        {
            std::lock_guard guard(mutex);
            if (instance == nullptr)
            {
                auto* ptr = new Singleton2;
                std::atomic_thread_fence(std::memory_order_seq_cst);
                instance = ptr;
            }
        }
        return instance;
    }

    static void deleteInstance()
    {
        std::lock_guard guard(mutex);
        if (instance != nullptr)
        {
            delete instance;
            instance = nullptr;
        }
    }

    [[nodiscard]] int getData() const
    {
        return this->data;
    }

    void setData(int value)
    {
        this->data = value;
    }

private:
    Singleton2() = default;
    ~Singleton2()
    {
        std::cout << "Singleton2 Destruct." << std::endl;
    }

    struct Deleter
    {
        ~Deleter()
        {
            Singleton2::deleteInstance();
        }
    };
    static Deleter deleter;


    static Singleton2* instance;
    static std::mutex mutex;

    int data{};
};

Singleton2* Singleton2::instance;
std::mutex Singleton2::mutex;
Singleton2::Deleter Singleton2::deleter;


int main()
{
    Singleton::get()->setData(5);
    std::cout << "singleton: " << Singleton::get()->getData() << std::endl;

    Singleton2::get()->setData(6);
    std::cout << "singleton2: " << Singleton2::get()->getData() << std::endl;
//    Singleton2::deleteInstance();

    return 0;
}